﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace UtilLib
{
    public static class IOUtil
    {
        #region Stream
        /// <summary>
        /// Reads the fully.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <returns>bytes</returns>
        public static byte[] ReadFully(Stream stream)
        {
            return ReadFully(stream, 0);
        }
        /// <summary>
        /// Reads data from a stream until the end is reached. The
        /// data is returned as a byte array. An IOException is
        /// thrown if any of the underlying IO calls fail.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        /// <param name="initialLength">The initial buffer length</param>
        /// <returns>bytes</returns>
        public static byte[] ReadFully(Stream stream, int initialLength)
        {
            // If we've been passed an unhelpful initial length, just
            // use 32K.
            if (initialLength < 1)
            {
                initialLength = 32768;
            }

            byte[] buffer = new byte[initialLength];
            int read = 0;

            int chunk;
            while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
            {
                read += chunk;

                // If we've reached the end of our buffer, check to see if there's
                // any more information
                if (read == buffer.Length)
                {
                    int nextByte = stream.ReadByte();

                    // End of stream? If so, we're done
                    if (nextByte == -1)
                    {
                        return buffer;
                    }

                    // Nope. Resize the buffer, put in the byte we've just
                    // read, and continue
                    byte[] newBuffer = new byte[buffer.Length * 2];
                    Array.Copy(buffer, newBuffer, buffer.Length);
                    newBuffer[read] = (byte)nextByte;
                    buffer = newBuffer;
                    read++;
                }
            }
            // Buffer is now too big. Shrink it.
            byte[] ret = new byte[read];
            Array.Copy(buffer, ret, read);
            return ret;
        }
        #endregion

        #region File
        /// <summary>
        /// Unpacks the files.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="dir">The dir.</param>
        /// <returns>if succeed return true,otherwise false.</returns>
        public static bool UnpackFiles(string file, string dir)
        {
            if (!File.Exists(file)) return false;
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            FastZip fz = new FastZip();
            fz.ExtractZip(file, dir, string.Empty);
            return true;
        }
        /// <summary>
        /// Create a Zip archive.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <param name="directory">The directory to Zip.</param>
        public static void PackFiles(string filename, string directory)
        {
            if (!Directory.Exists(directory)) return;
            FastZip fz = new FastZip();
            fz.CreateEmptyDirectories = true;
            fz.CreateZip(filename, directory, true, "");
            fz = null;
        }

        /// <summary>
        /// Extract file name from given phisical server path
        /// </summary>
        /// <param name="path">
        /// The Server path.
        /// </param>
        /// <returns>
        /// The File Name.
        /// </returns>
        public static string GetLastPathFromPath(string path)
        {
            if (String.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            return path.Substring(path.LastIndexOf("\\")).Replace("\\", string.Empty);
        }
        /// <summary>
        /// Move file or folder to special path
        /// </summary>
        /// <param name="currentFile">a file name or a dir name</param>
        /// <param name="destinationPath"> destination Path</param>
        /// <returns></returns>
        public static bool MoveFileToPath(string currentFile, string destinationPath, bool isCopy)
        {
            if (!File.Exists(currentFile)) return false;
            if (!System.IO.Directory.Exists(destinationPath))
                System.IO.Directory.CreateDirectory(destinationPath);
            if (isCopy)
                File.Copy(currentFile, System.IO.Path.Combine(destinationPath, System.IO.Path.GetFileName(currentFile)), true);
            else
            {
                if (File.Exists(System.IO.Path.Combine(destinationPath, System.IO.Path.GetFileName(currentFile))))
                    File.Delete(System.IO.Path.Combine(destinationPath, System.IO.Path.GetFileName(currentFile)));
                File.Move(currentFile, System.IO.Path.Combine(destinationPath, System.IO.Path.GetFileName(currentFile)));
            }
            return true;
        }
        /// <summary>
        /// Move file or folder to special path
        /// </summary>
        /// <param name="currentFile">a file name or a dir name</param>
        /// <param name="destinationPath"> destination Path</param>
        /// <param name="newFileName">new file name include extension</param>
        /// <returns></returns>
        public static bool MoveFileToPath(string currentFile, string destinationPath, string newFileName, bool isCopy)
        {
            System.Security.AccessControl.DirectorySecurity security = new System.Security.AccessControl.DirectorySecurity();

            if (!File.Exists(currentFile)) return false;
            if (!System.IO.Directory.Exists(destinationPath))
                System.IO.Directory.CreateDirectory(destinationPath);
            if (isCopy)
                File.Copy(currentFile, System.IO.Path.Combine(destinationPath, newFileName), true);
            else
            {
                if (File.Exists(System.IO.Path.Combine(destinationPath, newFileName)))
                    File.Delete(System.IO.Path.Combine(destinationPath, newFileName));
                File.Move(currentFile, System.IO.Path.Combine(destinationPath, newFileName));
            }
            return true;
        }

        public static bool MovePathToPath(string currentPath, string destinationPath, bool recursive)
        {
            if (!System.IO.Directory.Exists(currentPath)) return false;
            if (currentPath == System.IO.Path.GetDirectoryName(destinationPath)) return true;
            if (!System.IO.Directory.Exists(destinationPath))
                System.IO.Directory.CreateDirectory(destinationPath);
            System.IO.Directory.GetFiles(currentPath).ToList().
                ForEach(f =>
                    {
                        MoveFileToPath(f, destinationPath, false);
                        if (!IsHaveFiles(System.IO.Path.GetDirectoryName(f), true))
                        {
                            System.IO.Directory.Delete(System.IO.Path.GetDirectoryName(f), true);
                        }
                    });
            if (System.IO.Directory.Exists(currentPath))
            {
                System.IO.Directory.GetDirectories(currentPath).ToList().
                    ForEach(d =>
                        {
                            MovePathToPath(d, System.IO.Path.Combine(destinationPath, GetLastPathFromPath(d)), true);
                            if (!IsHaveFiles(System.IO.Path.GetDirectoryName(d), true))
                            {
                                System.IO.Directory.Delete(System.IO.Path.GetDirectoryName(d), true);
                            }
                        });
            }

            return true;
        }
        /// <summary>
        /// Set file property to normal
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static bool SetFile2Normal(string filename)
        {
            if (System.IO.File.Exists(filename))
            {
                new FileInfo(filename) { Attributes = System.IO.FileAttributes.Normal };
                return true;
            }
            return false;
        }

        public static bool SetDirectory2Normal(string directory)
        {
            if (System.IO.Directory.Exists(directory))
            {
                new DirectoryInfo(directory) { Attributes = System.IO.FileAttributes.Normal };
                return true;
            }
            return false;
        }

        public static bool IsHaveFiles(string Path, bool recursive)
        {
            if (System.IO.Directory.GetFiles(Path).Count() != 0) return true;
            if (recursive && System.IO.Directory.GetDirectories(Path).Count() != 0)
            {
                foreach (var childPath in System.IO.Directory.GetDirectories(Path))
                {
                    if (IsHaveFiles(childPath, recursive))
                        return true;
                }
            }
            return false;
        }
        #endregion
    }
}
